package com.sunriz.javafx.server.utils.Scada;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sunriz.javafx.server.Constant.ScadaConstant;
import com.sunriz.javafx.server.model.DTO.AddressInfo;
import com.sunriz.javafx.server.model.DTO.ScadaConfigDTO;
import javafx.scene.control.Alert;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * ClassName: ScadaConfigUtil
 * Package: com.sunriz.javafx.server.utils
 * Description:
 * scada配置文件的读取与更新
 *
 * @Author BuTang
 * @Create 2024/12/24 10:43
 * @Version 1.0
 */
@Slf4j
@Data
public class ScadaConfigUtil {


    /**
     * 用于存储转换后的 ScadaConfigDTO 对象的列表
     */
    private static List<ScadaConfigDTO> scadaConfigList = new ArrayList<>();

    /**
     * 私有构造函数，防止类被实例化
     */
    private ScadaConfigUtil() {
        throw new AssertionError("Utility class cannot be instantiated.");
    }


    /**
     * 获取文件夹列表
     * @return list文件列表
     */
    public static List<String> getFileList(){
        List<String> fileNames = new ArrayList<>();
        File dir = new File(ScadaConstant.FILE_PATH);

        // 检查目录是否存在且是一个有效的目录
        if (dir.exists() && dir.isDirectory()) {
            // 获取目录中的所有文件和子目录
            File[] files = dir.listFiles();

            if (files != null) {
                // 遍历所有文件
                for (File file : files) {
                    if (file.isFile()) {
                        // 如果是文件，添加文件名到列表
                        fileNames.add(file.getName());
                    }
                }
            }
        } else {
            System.out.println("指定路径不存在或不是一个目录！");
        }

        return fileNames;
    }


    /**
     * 获取scadaConfig配置文件
     * @return 将配置数据作为一个集合返回
     */
    public static List<ScadaConfigDTO> readScadaConfig() {
        List<ScadaConfigDTO> data = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String s = ScadaConstant.FILE_PATH + ScadaConstant.fileName;
            File file = new File(s);
            // 反序列化 JSON 为 List<ScadaConfigDTO> 对象
            data = objectMapper.readValue(file, new TypeReference<List<ScadaConfigDTO>>() {
            });
        } catch (IOException e) {
            log.info("ScadaConfigUtil中，反序列化 JSON 为 List<ScadaConfigDTO> 对象出错");
//            e.printStackTrace();
        }
            return data;
    }


    /**
     * 树数据转换为 List<ScadaConfigDTO> 且保存到文件中
     * @param treeView 树状图
     */
    public static void updateScadaConfig(TreeView<String> treeView) {
        // 获取树的根节点
        TreeItem<String> root = treeView.getRoot();

        // 清空现有列表
        scadaConfigList.clear();

        // 递归遍历树并将其转换为 ScadaConfigDTO（跳过根节点）,传递一个标识参数来跳过根节点
        boolean b = convertTreeToList(root, true);
        if (!b){
            return;
        }

        ObjectMapper mapper = new ObjectMapper();
        // false 表示不追加，清空原有内容
        try (FileWriter file = new FileWriter(ScadaConstant.FILE_PATH + ScadaConstant.fileName, false)) {
            String s = mapper.writeValueAsString(scadaConfigList);
            file.write(s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 递归遍历树，并将每个节点转换为 ScadaConfigDTO
     * @param item
     * @param isRoot
     */
    private static boolean convertTreeToList(TreeItem<String> item, boolean isRoot) {
        if (item == null) {
            return true;
        }

        // 跳过根节点（根据 isRoot 标识）
        if (isRoot) {
            // 递归调用子节点，但不处理根节点
            for (TreeItem<String> child : item.getChildren()) {
                // 设置 isRoot 为 false，表示开始处理下一级节点
                convertTreeToList(child, false);
            }
            return true;
        }

        // 获取当前节点的 slaveId (假设 item.getValue() 为 slaveId)
        String slaveId = item.getValue();
        List<AddressInfo> infos = new ArrayList<>();

        // 递归获取所有子节点作为 addresses，假设子节点的值是地址
        for (TreeItem<String> child : item.getChildren()) {
            try {
                // 假设子节点的值可以转换为整数地址
                infos.add(new AddressInfo(Integer.parseInt(child.getValue()),"null") );
            } catch (NumberFormatException e) {
                // 弹出一个简洁的错误提示框
                Alert alert = new Alert(Alert.AlertType.ERROR, "无法解析地址值: " + child.getValue());
                alert.setTitle("输入错误");
                alert.setHeaderText(null); // 移除头部标题
                alert.setContentText("请输入有效的整数地址值。"); // 提供具体的错误信息
                alert.showAndWait(); // 显示弹出框
                return false;
            }
        }

        // 如果有有效的地址，则创建并保存 ScadaConfigDTO
        if (!infos.isEmpty()) {
            ScadaConfigDTO configDTO = new ScadaConfigDTO(slaveId, infos);
            scadaConfigList.add(configDTO);
        }

        // 递归遍历子节点
        for (TreeItem<String> child : item.getChildren()) {
            // 继续递归处理子节点
            convertTreeToList(child, false);
        }
        return true;
    }

}
